package com.XZDP.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.XZDP.controller.BlogController;
import com.XZDP.dto.Result;
import com.XZDP.dto.ScrollResult;
import com.XZDP.dto.UserDTO;
import com.XZDP.entity.Blog;
import com.XZDP.entity.User;
import com.XZDP.mapper.BlogMapper;
import com.XZDP.service.IBlogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.XZDP.service.IFollowService;
import com.XZDP.service.IUserService;
import com.XZDP.utils.Constant.RedisConstant;
import com.XZDP.utils.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;


@Service
@Slf4j
public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private IUserService userService;
    @Autowired
    private IFollowService followService;
    @Autowired
    private BlogController blogController;

    private static final ObjectMapper objectMapper = new ObjectMapper();


    /**
     * 点赞功能,引入redis判断当前用户是否点赞
     *
     * @param id
     * @return
     */
    @Override
    public Result likeBlog(Long id) {
        String key = RedisConstant.ISBLOG_KEY + id;
        //获取当前用户ID
        Long userId = UserHolder.getUser().getId();
        //判断当前用户是否点赞
        Double score = redisTemplate.opsForZSet().score(key, userId.toString());
        if (score != null) {
            //已经点赞,redis移除用户,数据库减点赞数
            redisTemplate.opsForZSet().remove(key, userId.toString());
            update().setSql("liked = liked - 1").eq("id", id).update();
        } else {
            //当前用户未点赞
            //添加redis
            redisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis());
            update().setSql("liked = liked + 1").eq("id", id).update();
        }
        return Result.ok();
    }


    /**
     * 点赞排行榜功能
     *
     * @param id
     * @return
     */
    public Result likeBlogList(Long id) {
        String key = RedisConstant.ISBLOG_KEY + id;
        //查询排名前五的用户数据，返回集合
        Set<String> LikeList = redisTemplate.opsForZSet().range(key, 0, 4);
        List<User> userList = new ArrayList<>();
        for (String s : LikeList) {
            try {
                User user = userService.getById(objectMapper.readValue(s, Long.class));
                User user2 = new User();
                user2.setId(user.getId());
                user2.setIcon(user.getIcon());
                userList.add(user2);
            } catch (JsonProcessingException e) {
                throw new RuntimeException(e);
            }
        }
        Collections.reverse(userList);
        return Result.ok(userList);
    }

    @Override
    public Result saveBlog(Blog blog) {
        // 获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 保存探店博文
        boolean save = save(blog);
        if (save) {
            //保存成功
            //查询所有粉丝
            List<Long> followIdList = followService.getByUserID(UserHolder.getUser().getId());
            //将该笔记ID保存到所有粉丝的redis‘邮箱’
            for (Long fllowid : followIdList) {
                redisTemplate.opsForZSet().add(RedisConstant.USER_BLOG_KEY + fllowid, String.valueOf(blog.getId()), System.currentTimeMillis());
            }
        }
        // 返回id
        return Result.ok(blog.getId());
    }

    /**
     * @param lastId 上一次最小时间戳就是这次最大MAX
     * @param offset 偏移量，上一次与最小时间戳相同的个数
     * @return
     */
    @Override
    public Result queryFollowBlog(Long lastId, Integer offset) {
        List<Blog> blogList = new ArrayList<>();
        List<Long> ids = new ArrayList<>();
        ScrollResult scrollResult = new ScrollResult();
        //根据lastid和offset查询redis
        Set<ZSetOperations.TypedTuple<String>> typedTuples =
                redisTemplate.opsForZSet().reverseRangeByScoreWithScores(
                        RedisConstant.USER_BLOG_KEY + UserHolder.getUser().getId(),
                        0, lastId, offset, 2);
        if (typedTuples == null || typedTuples.isEmpty()) {
            return Result.ok();
        }
        //解析结果，分析本次最小时间戳，偏移量
        Long mintime = 0L;
        int count = 1;//每一次与最小时间戳相同的时间戳个数即为下一次的偏移量
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) {
            long score = tuple.getScore().longValue();//每一次的时间戳
            if (score == mintime) {
                //与最小时间戳相等
                count++;
            } else {
                //不相等
                mintime = score;
                count = 1;
            }
            String value = tuple.getValue();//每一次的文章ID
            ids.add(Long.valueOf(value));//存入文章id集合
        }
        //根据ids集合查询文章信息
        for (Long id : ids) {
            blogList.add(getById(id));
        }
        //完善文章信息
        for (Blog blog : blogList) {
            blogController.islike(blog);
            User user = userService.getById(blog.getUserId());
            blog.setName(user.getNickName());
            blog.setIcon(user.getIcon());
        }
        //封装返回
        scrollResult.setList(blogList);
        scrollResult.setOffset(count);
        scrollResult.setMinTime(mintime);
        return Result.ok(scrollResult);
    }
}
